/*
 * Copyright (C) 2014 Wei Chou (weichou2010@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.wei.c.widget;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;

import com.wei.c.lib.R;

public class DotLoadingView extends View {
	private static final int TIME_INTERVAL		= 1000;
	private static final int HORIZONTAL			= 0;
	private static final int VERTICAL			= 1;

	private Drawable mDotA, mDotB, mDotC;
	private int mGap;
	private int mOrientation = HORIZONTAL;
	private int mTimeInterval = TIME_INTERVAL;
	private boolean mStop = false;

	private int mHeaderDotIndex;
	private boolean mLeft = false;
	Drawable mDotDrawAt0 = null, mDotDrawAt1 = null, mDotDrawAt2 = null;

	public DotLoadingView(Context context) {
		super(context);
		init(null);
	}

	public DotLoadingView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context.obtainStyledAttributes(attrs, R.styleable.DotLoadingView, 0, 0));
	}

	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	public DotLoadingView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context.obtainStyledAttributes(attrs, R.styleable.DotLoadingView, defStyle, 0));
	}

	private void init(TypedArray a) {
		setWillNotDraw(false);
		if (a != null) {
			setGap(a.getDimensionPixelOffset(R.styleable.DotLoadingView_dotLoadingGap, 0));
			setOrientation(a.getInt(R.styleable.DotLoadingView_dotOrientation, HORIZONTAL));
			setTimeInterval(a.getInt(R.styleable.DotLoadingView_dotLoadingTimeInterval, TIME_INTERVAL));
			setDotA(a.getDrawable(R.styleable.DotLoadingView_dotLoadingSrcA));
			setDotB(a.getDrawable(R.styleable.DotLoadingView_dotLoadingSrcB));
			setDotC(a.getDrawable(R.styleable.DotLoadingView_dotLoadingSrcC));

			a.recycle();
		}
	}

	public void setGap(int gapPx) {
		if (gapPx != mGap) {
			mGap = gapPx;
			requestLayout();
			invalidate();
		}
	}

	public void setOrientation(int orientation) {
		if ((orientation == HORIZONTAL || orientation == VERTICAL) && mOrientation != orientation) {
			mOrientation = orientation;
			requestLayout();
			invalidate();
		}
	}

	public void setTimeInterval(int timeMillis) {
		mTimeInterval = timeMillis;
	}

	public void setDotA(int drawableId) {
		setDotA(getResources().getDrawable(drawableId));
	}

	public void setDotA(Drawable drawable) {
		setDotInner(drawable, 'A');
	}

	public void setDotB(int drawableId) {
		setDotB(getResources().getDrawable(drawableId));
	}

	public void setDotB(Drawable drawable) {
		setDotInner(drawable, 'B');
	}

	public void setDotC(int drawableId) {
		setDotC(getResources().getDrawable(drawableId));
	}

	public void setDotC(Drawable drawable) {
		setDotInner(drawable, 'C');
	}

	private void setDotInner(Drawable drawable, char abc) {
		boolean changed = false;
		switch (abc) {
		case 'A':
			if (mDotA != drawable) {
				if (mDotA != null) {
					mDotA.setCallback(null);
				}
				mDotA = drawable;
				if (mDotA != null) {
					mDotA.setBounds(0, 0, mDotA.getIntrinsicWidth(), mDotA.getIntrinsicHeight());
					mDotA.setCallback(this);
				}
				changed = true;
			}
			break;
		case 'B':
			if (mDotB != drawable) {
				if (mDotB != null) {
					mDotB.setCallback(null);
				}
				mDotB = drawable;
				if (mDotB != null) {
					mDotB.setBounds(0, 0, mDotB.getIntrinsicWidth(), mDotB.getIntrinsicHeight());
					mDotB.setCallback(this);
				}
				changed = true;
			}
			break;
		case 'C':
			if (mDotC != drawable) {
				if (mDotC != null) {
					mDotC.setCallback(null);
				}
				mDotC = drawable;
				if (mDotC != null) {
					mDotC.setBounds(0, 0, mDotC.getIntrinsicWidth(), mDotC.getIntrinsicHeight());
					mDotC.setCallback(this);
				}
				changed = true;
			}
			break;
		default:
			break;
		}
		if (changed) {
			requestLayout();
			invalidate();
		}
	}

	public void start() {
		mStop = false;
		startInner();
	}

	public void stop() {
		mStop = true;
		removeCallbacks(mInvervalRun);
	}

	private void startInner() {
		removeCallbacks(mInvervalRun);
		postDelayed(mInvervalRun, mTimeInterval);
	}

	@Override
	protected void onAttachedToWindow() {
		super.onAttachedToWindow();
		if (!mStop) startInner();
	}

	@Override
	protected void onDetachedFromWindow() {
		removeCallbacks(mInvervalRun);
		super.onDetachedFromWindow();
	}

	/*这里会导致定时不准确
	@Override
	public void computeScroll() {
		if (!mStop) postDelayed(mInvervalRun, mTimeInterval);
		super.computeScroll();
	}*/

	private final Runnable mInvervalRun = new Runnable() {

		@Override
		public void run() {
			switch (mHeaderDotIndex) {
			case 0:
				mDotDrawAt0 = mDotA;
				mDotDrawAt1 = mDotB;
				mDotDrawAt2 = mDotC;
				mLeft = false;
				mHeaderDotIndex = 1;
				break;
			case 1:
				if (mLeft) {
					mDotDrawAt0 = mDotC;
					mDotDrawAt1 = mDotA;
					mDotDrawAt2 = mDotB;
				} else {
					mDotDrawAt0 = mDotB;
					mDotDrawAt1 = mDotA;
					mDotDrawAt2 = mDotC;
				}
				mHeaderDotIndex = mLeft ? 0 : 2;
				break;
			case 2:
				mDotDrawAt0 = mDotC;
				mDotDrawAt1 = mDotB;
				mDotDrawAt2 = mDotA;
				mLeft = true;
				mHeaderDotIndex = 1;
				break;
			default:
				break;
			}

			startInner();
			invalidate();
		}
	};

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int mode = MeasureSpec.getMode(widthMeasureSpec);
		Rect boundsA = mDotA.getBounds();
		Rect boundsB = mDotB.getBounds();
		Rect boundsC = mDotC.getBounds();
		if (mode == MeasureSpec.EXACTLY) {
			super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		} else {
			int measuredWidth = getPaddingLeft() + getPaddingRight();
			int measuredHeight = getPaddingTop() + getPaddingBottom();
			if (mOrientation == HORIZONTAL) {
				measuredWidth += boundsA.width() + mGap + boundsB.width() + mGap + boundsC.width();
				measuredHeight += Math.max(Math.max(boundsA.height(), boundsB.height()), boundsC.height());
			} else {
				measuredWidth += Math.max(Math.max(boundsA.width(), boundsB.width()), boundsC.width());
				measuredHeight += boundsA.height() + mGap + boundsB.height() + mGap + boundsC.height();
			}
			setMeasuredDimension(measuredWidth, measuredHeight);
		}
		if (mOrientation == HORIZONTAL) {
			int contentHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
			if (boundsA.width() <= 0 || boundsA.height() <= 0) {
				mDotA.setBounds(0, 0, contentHeight, contentHeight);
			}
			if (boundsB.width() <= 0 || boundsB.height() <= 0) {
				mDotB.setBounds(0, 0, contentHeight, contentHeight);
			}
			if (boundsC.width() <= 0 || boundsC.height() <= 0) {
				mDotC.setBounds(0, 0, contentHeight, contentHeight);
			}
		} else {
			int contentWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
			if (boundsA.width() <= 0 || boundsA.height() <= 0) {
				mDotA.setBounds(0, 0, contentWidth, contentWidth);
			}
			if (boundsB.width() <= 0 || boundsB.height() <= 0) {
				mDotB.setBounds(0, 0, contentWidth, contentWidth);
			}
			if (boundsC.width() <= 0 || boundsC.height() <= 0) {
				mDotC.setBounds(0, 0, contentWidth, contentWidth);
			}
		}
	}

	@Override
	protected void onDraw(Canvas canvas) {
		int saveCount = canvas.save();
		int paddingLeft = getPaddingLeft();
		int paddingTop = getPaddingTop();
		int paddingRight = getPaddingRight();
		int paddingBottom = getPaddingBottom();
		int contentWidth = getWidth() - paddingLeft - paddingRight;
		int contentHeight = getHeight() - paddingTop - paddingBottom;

		canvas.clipRect(paddingLeft, paddingTop, contentWidth - paddingLeft, contentHeight - paddingTop);
		int left;
		int top;
		Rect bounds0 = mDotDrawAt0.getBounds();
		Rect bounds1 = mDotDrawAt1.getBounds();
		Rect bounds2 = mDotDrawAt2.getBounds();
		if (mOrientation == HORIZONTAL) {
			left = 0;
			top = (contentHeight - bounds0.height()) / 2;
		} else {
			left = (contentWidth - bounds0.width()) / 2;
			top = 0;
		}
		canvas.translate(left, top);
		mDotDrawAt0.draw(canvas);
		canvas.translate(-left, -top);
		if (mOrientation == HORIZONTAL) {
			left = bounds0.width() + mGap;
			top = (contentHeight - bounds1.height()) / 2;
		} else {
			left = (contentWidth - bounds1.width()) / 2;
			top = bounds0.height() + mGap;
		}
		canvas.translate(left, top);
		mDotDrawAt1.draw(canvas);
		canvas.translate(-left, -top);
		if (mOrientation == HORIZONTAL) {
			left = bounds0.width() + mGap + bounds1.width() + mGap;
			top = (contentHeight - bounds2.height()) / 2;
		} else {
			left = (contentWidth - bounds2.width()) / 2;
			top = bounds0.height() + mGap + bounds1.height() + mGap;
		}
		canvas.translate(left, top);
		mDotDrawAt2.draw(canvas);
		canvas.translate(-left, -top);

		canvas.restoreToCount(saveCount);
	}
}
